﻿using ChessTest.Chess.Items;
using org.xisoft.game.utils.game;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Threading;

namespace ChessTest.Chess.Algorithms
{
    /// <summary>
    /// 多线程算法
    /// </summary>
    public class MulThreadAlgorithm<Algorithm> : AiAlgorithm
        where Algorithm : AiAlgorithm
    {
        public override MoveAction Search(AiChessboard aiChessboard, int depth)
        {
            MoveAction bestChildstep = null;
            Object obj = new object();

            Action<MoveAction> action = step =>
            {
                if (step == null) return;
                lock (obj)
                {
                    if (bestChildstep == null || bestChildstep.Score < step.Score|| (bestChildstep.Score == step.Score  &&( bestChildstep.OldChessman ==null && step.OldChessman!=null) ))
                    {
                        bestChildstep = step;
                        if (step.CurrentChessman != null)
                            bestChildstep.CurrentChessman = aiChessboard.GetChessman(step.FromX, step.FromY);
                        if (step.OldChessman != null)
                            bestChildstep.OldChessman = aiChessboard.GetChessman(step.ToX, step.ToY);

                    }
                }
            };
            List<SearchTask> searchTaskList = new List<SearchTask>();
            aiChessboard.ForeachMoviesChess(chessman =>
            {
                AiChessboard anotherChessboard = (AiChessboard)aiChessboard.Clone();
                Chessman man = anotherChessboard.GetChessman(chessman.PositionX, chessman.PositionY);
                SearchTask task = new SearchTask(anotherChessboard, depth, man, action);
                searchTaskList.Add(task);
                task.Start();
            });

            foreach (SearchTask task in searchTaskList)
                task.WaitForComplete();


            return bestChildstep;
        }







        class SearchTask
        {
            private readonly Action<MoveAction> action;
            private readonly AiChessboard aiChessboard;
            private readonly int depth;
            private readonly Chessman chessman;
            private Type algorithmType;
            public SearchTask(AiChessboard aiChessboard, int depth, Chessman chessman, Action<MoveAction> action)
            {
                this.action = action;
                this.aiChessboard = aiChessboard;
                this.depth = depth;
                this.chessman = chessman;

                algorithmType = typeof(Algorithm);
            }

            Thread thread;

            public void Start()
            {
                thread = new Thread(Run)
                {
                    IsBackground = true
                };
                thread.Start();

            }

            public void Run()
            {
                MoveAction bestChildstep = null;

                List<Point> points = chessman.GetCanMoveList(aiChessboard);
                foreach (Point point in points)
                {
                    Chessman man = aiChessboard.GetChessman(point.X, point.Y);

                    aiChessboard.Move(chessman, point.X, point.Y);

                    MoveAction step = Search(aiChessboard, depth - 1);


                    long score = -step.Score;
                    if (man != null)
                        score += man.Score;

                    aiChessboard.Undo();
                    if (bestChildstep == null || bestChildstep.Score < score || (bestChildstep.Score == score && (man != null && bestChildstep.OldChessman != null && bestChildstep.OldChessman.Score < man.Score)))
                    {
                        if (bestChildstep == null)
                            bestChildstep = new MoveAction();
                        bestChildstep.Score = score;
                        bestChildstep.CurrentChessman = chessman;
                        bestChildstep.ToX = point.X;
                        bestChildstep.ToY = point.Y;
                        bestChildstep.FromX = chessman.PositionX;
                        bestChildstep.FromY = chessman.PositionY;
                        bestChildstep.OldChessman = man;

                    }
                }

                action(bestChildstep);
                thread = null;
            }

            public void WaitForComplete()
            {
                Thread thread = this.thread;
                if (thread != null)
                    thread.Join();
            }

            protected MoveAction Search(AiChessboard aiChessboard, int depth)
            {

                Algorithm al = Activator.CreateInstance(algorithmType, aiChessboard) as Algorithm;
                return al.Search(aiChessboard, depth);
            }
        }
    }
}
